﻿namespace LogManager.Gui.ViewModels
{
    using System.Collections.ObjectModel;
    using System.Linq;
    using LogManager.Core.Infrastructure.Logging;
    using LogManager.Core.Models;
    using LogManager.Gui.AppStart;
    using LogManager.Gui.Factories;
    using LogManager.Gui.Views;
    using LogManager.Utils.Unity;
    using Microsoft.Practices.Unity;
    using Microsoft.Practices.Unity.InterceptionExtension;
    using NSubstitute;
    using NUnit.Framework;

    [TestFixture]
    public class TestServerViewModel
    {
        [Test]
        public void ServerViewModel_Ctor_BasicSetUp_Ok()
        {
            var view = Substitute.For<IServerView>();
            var mainViewModel = Substitute.For<IMainViewModel>();
            var server = Substitute.For<IServer>();
            var factory = Substitute.For<IViewModelFactory>();
            var collection = new ObservableCollection<ILocation>();
            server.Locations.Returns(collection);
            var viewModel = new ServerViewModel(view, mainViewModel, server, factory);

            Assert.AreEqual(viewModel.View, view);
            Assert.AreEqual(viewModel.Server, server);
        }

        [Test]
        public void ServerViewModel_LocationsVm_CheckCollectionIsSync_Ok()
        {
            var view = Substitute.For<IServerView>();
            var mainViewModel = Substitute.For<IMainViewModel>();
            var server = Substitute.For<IServer>();
            var factory = Substitute.For<IViewModelFactory>();
            var collection = new ObservableCollection<ILocation>();
            server.Locations.Returns(collection);
            var viewModel = new ServerViewModel(view, mainViewModel, server, factory);

            Assert.AreEqual(0, viewModel.LocationsVm.Count);

            // when
            var location1 = Substitute.For<ILocation>();
            var locationviewModel1 = Substitute.For<ILocationViewModel>();
            factory.CreateLocationViewModel(location1).Returns(locationviewModel1);
            collection.Add(location1);

            Assert.AreEqual(1, viewModel.LocationsVm.Count);
            Assert.AreEqual(locationviewModel1, viewModel.LocationsVm.First());

            // when
            var location2 = Substitute.For<ILocation>();
            var locationviewModel2 = Substitute.For<ILocationViewModel>();
            factory.CreateLocationViewModel(location2).Returns(locationviewModel2);
            collection.Add(location2);

            Assert.AreEqual(2, viewModel.LocationsVm.Count);
            Assert.AreEqual(locationviewModel1, viewModel.LocationsVm.First());
            Assert.AreEqual(locationviewModel2, viewModel.LocationsVm.Skip(1).First());
        }

        [Test]
        public void ServerViewModel_DeleteServerCommand_Execute_ServerDeletedFromPlateform()
        {
            var viewmodel = CreateServerViewModel();

            using (var logTracker = new LogTracker(Log.Logger))
            {
                // When
                viewmodel.DeleteServerCommand.Execute(null);

                Assert.AreEqual(1, logTracker.Logs.Count);
                Assert.AreEqual(LogType.Info, logTracker.Logs.Single().LogType);
            }

            // Assert
            viewmodel.Server.Received().DeleteServer();
        }

        [Test]
        public void ServerViewModel_AddLocationCommand_Execute_NewLocationAdded()
        {
            var viewmodel = CreateServerViewModel();
            var collection = viewmodel.Server.Locations;
            var addedLocation = Substitute.For<ILocation>();
            viewmodel.Server.AddNewLocation().Returns(addedLocation);
            collection.Add(addedLocation);
            viewmodel.LocationsVm.Single().Location.Returns(addedLocation);

            using (var logTrakcker = new LogTracker(Log.Logger))
            {
                // When
                viewmodel.AddLocationCommand.Execute(null);

                Assert.AreEqual(1, logTrakcker.Logs.Count);
                Assert.AreEqual(LogType.Info, logTrakcker.Logs.Single().LogType);
            }

            // Assert
            viewmodel.Server.Received().AddNewLocation();
            viewmodel.MainViewModel.View.Received().ExpandAndSelectItem(viewmodel.LocationsVm.First());
        }

        private static ServerViewModel CreateInterceptedServerViewModel()
        {
            var container = new UnityContainer();
            AopBoot.ConfigureForInterception(container);
            container.RegisterForInterception<ServerViewModel>(new InterceptionBehavior<PropertyChangedBehavior>());

            var view = Substitute.For<IServerView>();
            var server = Substitute.For<IServer>();
            return container.Resolve<IServerView, IServer, ServerViewModel>(view, server);
        }

        private static ServerViewModel CreateServerViewModel()
        {
            var view = Substitute.For<IServerView>();
            var mainViewModel = Substitute.For<IMainViewModel>();
            var server = Substitute.For<IServer>();
            var factory = Substitute.For<IViewModelFactory>();
            var collection = new ObservableCollection<ILocation>();
            server.Locations.Returns(collection);
            return new ServerViewModel(view,mainViewModel, server, factory);
        }
    }
}
